using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Game {

public class Director:System.Object {
    private static Director Onlyinstance;
    public SceneController currentSceneController { get; set;}
    public static Director getInstance() {
        if (Onlyinstance==null){
            Onlyinstance = new Director();
        }
        return Onlyinstance;
    }
}
 

public class Lock {
    private static Lock OnlyInstance;
    public static int synLock;
    public static Lock getInstance() {
        if (OnlyInstance == null) {
            OnlyInstance = new Lock();
        }
        return OnlyInstance;
    }
    public Lock() {
        synLock = 1;
    }
    public int getLock() {
        return synLock;
    }
    public void setLock(int ll) {
        synLock = ll;
    }
}

public interface SceneController {
    void loadResources();
}


public interface UsersOperation {
    void figureClicked(figureControllor figureCon);/*click devil or priest to add it to boat*/
    void moveBoat();/*click boat to move it to opposite*/
    void restart();
}

public class MoveAction:MonoBehaviour {
    float speed = 2;
    int mov_flag = 0;//0:stop 1:in the middle of river 2:to opposite
    Vector3 dest;
    Vector3 middle;
    Lock synLock;
    void Update() {
        
        if (mov_flag == 1) {
            this.transform.position = Vector3.MoveTowards (transform.position, middle, speed*Time.deltaTime);
            if (transform.position == middle) {
                mov_flag = 2;
            }
        }else if(mov_flag == 2) {
             this.transform.position = Vector3.MoveTowards (transform.position, dest, speed*Time.deltaTime);
             if (transform.position == dest) {
                 synLock = Lock.getInstance();
                 synLock.setLock(1);
                 mov_flag = 0;
             }
        }
    }
    public void setDest(Vector3 Dest) {
        dest = Dest;
        middle = Dest;
        if (transform.position.y > Dest.y) {
            middle.y = transform.position.y;
        } else if (transform.position.y < Dest.y) {
            middle.x = transform.position.x;
        }
        mov_flag = 1;
    }
    public void reset() {
        mov_flag = 0;
    }
}

public class figureControllor {
    readonly GameObject figure;
    readonly MoveAction moveableScript;
    readonly ClickGUI clickGUI;
    coastControllor coastCon;
    int type = 0;
    bool onBoat;
    public figureControllor(string f_name) {
        if (f_name == "priest") {
            figure = Object.Instantiate(Resources.Load("Prefabs/Priest",typeof(GameObject)),Vector3.zero, Quaternion.identity,null) as GameObject;
            type = 0;
        } else if (f_name == "devil"){
            figure = Object.Instantiate(Resources.Load("Prefabs/Devil",typeof(GameObject)),Vector3.zero, Quaternion.identity,null) as GameObject;
            type = 1;
        } else {
            Debug.Log("error");
        }
        moveableScript = figure.AddComponent(typeof(MoveAction)) as MoveAction;
        clickGUI = figure.AddComponent(typeof(ClickGUI)) as ClickGUI;
        clickGUI.setCon (this);
    
    }
    public void setName(string name) {
        figure.name = name;
    }
    public void setPos(Vector3 pos) {
        figure.transform.position = pos;
    }
    public void moveToPos(Vector3 pos) {
        moveableScript.setDest(pos);
    }
    public string getName() {
        return figure.name;
    }
    public int getType() {
        return type;
    }
    public void moveToBoat(boatControllor boatCon) {
        coastCon = null;
        figure.transform.parent = boatCon.getGameobj().transform;
        onBoat = true;
    }
    public void moveToCoast(coastControllor newCoastCon) {
        coastCon = newCoastCon;
        figure.transform.parent = null;
        onBoat = false;
    }
    public bool IsOnBoat(){
        return onBoat;
    }
    public coastControllor getCoastControllor(){
        return coastCon;
    }
    public void reset() {
        moveableScript.reset();
        coastCon = (Director.getInstance().currentSceneController as FirstController).fromCoast;
        moveToCoast(coastCon);
        setPos(coastCon.getEmptyPosition());
        coastCon.moveToCoast(this);
    }
}

    public class coastControllor {
        readonly GameObject coast;
        readonly Vector3[] positions;
        readonly Vector3 fromPos = new Vector3(9,1,0);
        readonly Vector3 toPos = new Vector3(-9,1,0);
        int direction;
        figureControllor[] myFigures;
        public coastControllor(string _direction) {
            positions = new Vector3[] {new Vector3(6.5F,2.25F,0),new Vector3(7.5F,2.25F,0),new Vector3(8.5F,2.25F,0),
            new Vector3(9.5F,2.25F,0), new Vector3(10.5F,2.25F,0), new Vector3(11.5F,2.25F,0)};
            myFigures = new figureControllor[6];
            for (int i = 0; i < myFigures.Length; i++) {
                myFigures[i] = null;
            }
           
            if (_direction == "from") {
                coast = Object.Instantiate (Resources.Load ("Prefabs/Stone", typeof(GameObject)), fromPos, Quaternion.identity, null) as GameObject;
                coast.name = "from";
                direction = 1;
            } else {
                  coast = Object.Instantiate (Resources.Load ("Prefabs/Stone", typeof(GameObject)), toPos, Quaternion.identity, null) as GameObject;
                coast.name = "to";
                direction = -1;
            }
        }
        public int getEmptyIndex() {
            int i;
            for (i = 0;i < myFigures.Length; i++) {
                if (myFigures[i] == null) break;
            }
            return (i==myFigures.Length)?-1:i;
        }
        public Vector3 getEmptyPosition() {
            Vector3 pos;
            
            pos = positions[getEmptyIndex()];
            pos.x *= direction;
            return pos;
        }
        public void moveToCoast(figureControllor myfigure) {
            int i = getEmptyIndex();
            myFigures[i] = myfigure;
        }
        public figureControllor getOffCoast(string figureName) {
            for (int i = 0; i < myFigures.Length; i++) {
                if (myFigures[i] != null && myFigures[i].getName() == figureName) {
                    figureControllor figureCon = myFigures[i];
                    myFigures[i] = null;
                    return figureCon;
                }
                
            }
            return null;
        }
        
        public int getDirection(){
            return direction;
        }
        public int[] getFigureNum(){
            int[] count = {0,0};
            for (int i = 0; i < myFigures.Length; i++) {
                if (myFigures[i] != null) {
                    count[myFigures[i].getType()]++;
                }
            }
            return count;
        }
        public void reset() {
            myFigures = new figureControllor[6];
            for (int i = 0; i < myFigures.Length; i++) {
                myFigures[i] = null;
            }
        }
    }


    public class boatControllor {
        readonly GameObject boat;
        readonly MoveAction moveCon;
        readonly Vector3 fromPos = new Vector3 (5,1,0);
        readonly Vector3 toPos = new Vector3(-5,1,0);
        readonly Vector3[] from_pos;
        readonly Vector3[] to_pos;
        int direction;
        figureControllor[] myFigure = new figureControllor[2];

        public boatControllor() {
            direction = 1;
            from_pos = new Vector3[] {new Vector3 (4.5F, 1.5F, 0), new Vector3 (5.5F, 1.5F, 0)};
            to_pos = new Vector3[] {new Vector3 (-5.5F, 1.5F, 0), new Vector3 (-4.5F, 1.5F, 0)};
            boat = Object.Instantiate (Resources.Load ("Prefabs/Boat", typeof(GameObject)), fromPos, Quaternion.identity, null) as GameObject;
            boat.name = "boat";
            moveCon = boat.AddComponent(typeof(MoveAction)) as MoveAction;
            boat.AddComponent(typeof(ClickGUI));

        }
        public void Move() {
            if (direction == -1) {
                moveCon.setDest(fromPos);
                direction = 1;
            } else {
                moveCon.setDest(toPos);
                direction = -1;
            }
        }
        public int getEmptyIndex() {
            for (int i = 0; i < myFigure.Length; i++) {
                if (myFigure[i] == null) {
                    return i;
                }
            }
            return -1;
        }
        public bool isEmpty() {
            for (int i = 0; i < myFigure.Length; i++) {
                if (myFigure[i] != null) return false;
            }
            return true;
        }

        public Vector3 getEmptyPos() {
            Vector3 pos;
            int index = getEmptyIndex();
            if (direction == -1) {
                pos = to_pos[index];
            } else {
                pos = from_pos[index];
            }
            return pos;
        }
        public void moveToBoat(figureControllor tmp) {
            int index = getEmptyIndex();
            myFigure[index] = tmp;
        }
        public figureControllor GetOffBoat(string name) {
            for (int i = 0; i < myFigure.Length; i++) {
                if (myFigure[i] != null && myFigure[i].getName() == name) {
                    figureControllor ff = myFigure[i];
                    myFigure[i] = null;
                    return ff;
                }
            }
            return null;
        }
        public GameObject getGameobj() {
            return boat;
        }
        public int getDirection() {
            return direction;
        }
        public int[] getFigureNum(){
            int[] count = {0,0};
            for (int i = 0; i < myFigure.Length; i++) {
                if (myFigure[i] != null) {
                    count[myFigure[i].getType()]++;
                }
            }
            return count;
        }
        public void reset() {
            moveCon.reset();
            if (direction == -1) Move();
            myFigure = new figureControllor[2];
        }
    }

}